﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimioAPI;
using SimioAPI.Extensions;
using System.Collections;

namespace WLC
{
    public class StatisticElementDefinition : IElementDefinition
    {
        #region IElementDefinition Members

        public IElement CreateElement(IElementData data)
        {
            return new StatisticElement(data);
        }


        public void DefineSchema(IElementSchema schema)
        {
            IEventDefinition statisticUpdated = schema.EventDefinitions.AddEvent("StatisticUpdated");
            statisticUpdated.Description = "Is fired when any statistic is updated.";
            

        }

        public string Name
        {
            get { return "StatisticElement"; }
        }

        public string Description
        {
            get { return "Use the UpdateStatistic step to store statistics of any kind throughout the simulation."; }
        }

        public System.Drawing.Image Icon
        {
            get { return null; }
        }



        public static readonly Guid ID = new Guid("{7C0D8B38-6EF9-11DF-BF53-6012E0D72085}");

        public Guid UniqueID
        {
            get { return ID; }
        }

        #endregion
    }


    public class StatisticElement : IElement
    {
        // The hashtable to store the statistics in. Uses OrderType as key.
        Hashtable stats;

        public enum ValueTypes { avg, min, max, last, number, sum, deviation };

        IElementData _data;

        public StatisticElement(IElementData data)
        {
            stats = new Hashtable();
            _data = data;
        }



        #region IElement Members

        public void AddStatisticValue(string statisticName, double value)
        {

            SimStatistic thisStatistic;
            if (stats.ContainsKey(statisticName))
            {
                thisStatistic = (SimStatistic)stats[statisticName];

            }
            else
            {
                thisStatistic = new SimStatistic(statisticName);
                stats.Add(statisticName, thisStatistic);
            }

            thisStatistic.AddValue(value);

           // Fire the event StatisticUpdated
            _data.Events["StatisticUpdated"].Fire();


        }

        public double GetStatisticValue(string statisticName, ValueTypes type)
        {
            double value = 0;
                       
            SimStatistic thisStatistic = (SimStatistic)stats[statisticName];

            if (thisStatistic == null)
                return 0;


            if (type.Equals(ValueTypes.avg))
            {
                value = thisStatistic._avg;

            }
            else if (type.Equals(ValueTypes.max))
            {
                value = thisStatistic._max;
            }
            else if (type.Equals(ValueTypes.min))
            {
                value = thisStatistic._min;
            }
            else if (type.Equals(ValueTypes.last))
            {
                value = thisStatistic._last;
            }
            else if (type.Equals(ValueTypes.number))
            {
                value = thisStatistic._values.Count;
            }
            else if (type.Equals(ValueTypes.sum))
            {
                value = thisStatistic._sum;
            }
            else if (type.Equals(ValueTypes.deviation))
            {
                lock (thisStatistic._values)
                {
                    value = calculateDeviation(thisStatistic);
                }
            }

            return value;
        }

        private double calculateDeviation(SimStatistic thisStatistic)
        {
            double result = 0;
            
            ArrayList values = thisStatistic._values;
           
            int number = values.Count;

            double mean = thisStatistic._avg;

            foreach (double current in values)
            {
               result += Math.Pow((mean - current), 2);
            }

            return Math.Sqrt(result) / number;
        }


        public void Initialize()
        {

        }

        public void Shutdown()
        {
            // No shutdown code necessary
        }

        #endregion
    }

    class SimStatistic
    {
        public string _name;
        public double _min;
        public double _max;
        public double _avg;
        public double _sum;
        public double _last;
        public ArrayList _values;

        public SimStatistic(string name)
        {
            _name = name;
            _min = 0;
            _max = 0;
            _avg = 0;
            _sum = 0;
            _last = 0;
            _values = new ArrayList();
        }

        public void AddValue(double value)
        {

            _values.Add(value);

            if (_min > value)
                _min = value;

            if (_max < value)
                _max = value;

            _sum += value;

            _avg = _sum / _values.Count;
            _last = value;
        }
    }


}

